/*
 * ursax-crc32.h
 *
 *  Created on: Sep 22, 2015
 *      Author: zhangzm
 */

#ifndef URSAX_CRC32_H_
#define URSAX_CRC32_H_

// todo move to other file
#include "protocol.h"
#include "ursax.h"
#include "crc32.h"

#define CRC_BLOCK_BIT_MASK (CRC32_BLOCK_SIZE - 1)

#define CRC_NB_PER_BLOCK (SIZE_4K / sizeof(uint32_t))
#define CRC_NB_PER_BLOCK_MASK (CRC_NB_PER_BLOCK - 1)
#define CRC_BLK_TO_FILE_OFFSET(block_nb, crc_start_offset) (block_nb * SIZE_4K + crc_start_offset)
#define IS_4K_ALIGN(size) (((size)%SIZE_4K) == 0)
#define IS_512_ALIGN(size) ((size)%512 == 0)

struct ChecksumInfo
{
	uint64_t end;
	int32_t pre_len; // if offset is align, pre_len is 0
	int32_t mid_len; // data.length - ((CRC32_BLOCK_SIZE - pre_len) & CRC_BLOCK_BIT_MASK) - ((CRC32_BLOCK_SIZE - suf_len) & CRC_BLOCK_BIT_MASK)
	int32_t suf_len;  // if offset + data_len is align, suf_len is 0
	int32_t crc32_nb; // data's crc32 number
};

static inline void parse_range(uint64_t offset, uint32_t size, struct ChecksumInfo* ckinfo)
{
	uint64_t end = offset + size;
	ckinfo->end = end;
	ckinfo->pre_len = offset - LOWER_FLOOR(offset, CRC32_BLOCK_SIZE);
	ckinfo->suf_len = UPPER_FLOOR(end, CRC32_BLOCK_SIZE) - (end);
	ckinfo->mid_len = LOWER_FLOOR(end, CRC32_BLOCK_SIZE) - UPPER_FLOOR(offset, CRC32_BLOCK_SIZE);
	if(ckinfo->mid_len < 0){
		ckinfo->mid_len = 0;
	}
	// # : from offset to offset + size
	//  |   align length |   align length |   align length |   align length |
	//  |-----####################################################----------|
	//->| pre |<-        |              mid                |   ->|    suf   |<-
	if(LOWER_FLOOR(offset, CRC32_BLOCK_SIZE) == LOWER_FLOOR(end, CRC32_BLOCK_SIZE) && ckinfo->pre_len != 0){
		ckinfo->suf_len = 0;// ckinfo->mid_len == 0 too
	}

	ckinfo->crc32_nb = ckinfo->mid_len / CRC32_BLOCK_SIZE + !!ckinfo->pre_len + !!ckinfo->suf_len;;
}

static inline void crc32_4K_sequence(char* buf_, uint32_t size, uint32_t* out_crc32)
{
	crc32_4k_sequence_p3(buf_, size, out_crc32);
}


#endif /* URSAX_CRC32_H_ */
